﻿using Abp.AutoMapper;
using Abp.Dependency;
using GN.Pay.Application.GatewayApp.Dto.Input;
using GN.Pay.Application.GatewayApp.Dto.Output;
using GN.Pay.Core.Repositories;
using GN.Pay.Core.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GN.Pay.Application.GatewayApp.Impl
{
    /// <summary>
    /// 交易查询应用服务
    /// </summary>
    public class TradeQueryAppService : GatewayAppService, ITradeQueryAppService
    {
        private readonly IIocManager iocManager;

        /// <summary>
        /// 实例化 TradeQueryAppService 类新实例
        /// </summary>
        /// <param name="iocManager"></param>
        public TradeQueryAppService(IIocManager iocManager)
        {
            this.iocManager = iocManager;
        }

        /// <summary>
        /// 查询支付申请
        /// </summary>
        /// <param name="applyId"></param>
        /// <returns></returns>
        public PayApplyOutput QueryPayApply(PayApplyKeyInput input)
        {
            var repository = iocManager.Resolve<ITradePayApplyRepository>();
            var apply = repository.Get(input.ApplyId);
            if (apply == null)
            {
                return null;
            }
            var result = apply.MapTo<PayApplyOutput>();
            result.ApplyId = apply.Id;
            return result;
        }

        /// <summary>
        /// 所有交易通道查询
        /// </summary>
        /// <returns></returns>       
        public List<TradeChannelOutput> TradeChannelQuery(TradeChannelInput input)
        {
            var tradeCacheService = iocManager.Resolve<ITradeCacheService>();
            var channels = tradeCacheService.GetTradeChannels(input.AppId);
            return channels.Where(s => (s.ChannelType & input.ChannelType) != 0)
                .Select(s =>
                new TradeChannelOutput()
                {
                    ChannelId = s.ChannelId,
                    ChannelName = s.ChannelName,
                    ChannelType = s.ChannelType
                }).ToList();
        }

        /// <summary>
        /// 交易订单查询
        /// </summary>
        /// <param name="input">输入</param>
        /// <returns></returns>
        public OrderQueryOutput TradeOrderQuery(OrderInput input)
        {
            var repository = iocManager.Resolve<ITradeAccountBookRepository>();
            var channelRepository = iocManager.Resolve<ITradeChannelRepository>();
            var result = (from p in repository.GetAll()
                          join c in channelRepository.GetAll() on p.FirstChannelId equals c.Id
                          where p.AppId == input.AppId && p.OrderNo == input.OrderNo
                          select new OrderQueryOutput()
                          {
                              BookId = p.Id,
                              ApplyId = p.ApplyId,
                              Body = p.Body,
                              BookBalanceMoney = p.BookBalanceMoney,
                              BookTime = p.BookTime,
                              FirstChannelId = p.FirstChannelId,
                              FirstChannelName = c.ChannelName,
                              FirstPayTime = p.PayTime,
                              MemberNo = p.MemberNo,
                              OrderMoney = p.OrderMoney,
                              OrderNo = p.OrderNo,
                              OrderTime = p.OrderTime,
                              PayCount = p.PayCount,
                              PayFee = p.PayFee,
                              PayMoney = p.PayMoney,
                              RefundFee = p.RefundFee,
                              RefundMoney = p.RefundMoney,
                              Remark = p.Remark,
                              Subject = p.Subject,
                              TradeState = p.TradeState,
                              TradeBalanceMoney = p.TradeBalanceMoney
                          }
                     ).FirstOrDefault();
            if (result != null)
            {
                var bookChannelRepository = iocManager.Resolve<ITradeAccountBookChannelRepository>();
                result.PayChannels = (from b in bookChannelRepository.GetAll()
                                      join c in channelRepository.GetAll() on b.ChannelId equals c.Id
                                      where b.BookId == result.BookId
                                      orderby b.Id ascending
                                      select new OrderPayChannelOutput()
                                      {
                                          ApplyTime = b.ApplyTime,
                                          BankName = b.BankName,
                                          BankType = b.BankType,
                                          BookTime = b.BookTime,
                                          ChannelId = b.ChannelId,
                                          ChannelName = c.ChannelName,
                                          ChannelTradeNo = b.ChannelTradeNo,
                                          ClientIP = b.ClientIP,
                                          OtherPartyAccount = b.OtherPartyAccount,
                                          OtherPartyAccountId = b.OtherPartyAccountId,
                                          PayFee = b.PayFee,
                                          PayMoney = b.PayMoney,
                                          PayTime = b.PayTime,
                                          RefundFee = b.RefundFee,
                                          RefundMoney = b.RefundMoney,
                                          TradeNo = b.Id
                                      }).ToList();
            }
            return result;
        }

        /// <summary>
        /// 同步交易支付通道
        /// </summary>
        /// <param name="input">输入</param>
        /// <returns></returns>
        public SynTradePayChannelOutput SynTradePayChannel(OrderInput input)
        {
            var result = new SynTradePayChannelOutput();
            result.OrderNo = input.OrderNo;
            var repository = iocManager.Resolve<ITradePayApplyRepository>();
            var apply = repository.FirstOrDefault(s => s.AppId == input.AppId && s.OrderNo == input.OrderNo);
            if (apply != null)
            {
                result.ApplyId = apply.AppId;
                var items = apply.TradePayApplyChannels.ToList();
                if (items.Count > 0)
                {
                    result.ChannelCount = items.Count;
                    var syn = iocManager.Resolve<ITradeSynchronization>();
                    foreach (var item in items)
                    {
                        result.Channels.Add(item.ChannelId);
                        try
                        {
                            syn.TradeChannelPay(item.Id);
                        }
                        catch (Exception err)
                        {
                            this.Logger.Error("支付过期同步出错:" + err.Message, err);
                        }
                    }
                }
                else
                {
                    if (apply.IsExpire())
                    {
                        repository.Delete(apply);
                    }                   
                }
            }
            return result;
        }
    }
}
